﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;

using Utils;
using Utils.Cache;

namespace Utils
{
    public static class CacheExtensions
    {

        public static IServiceCollection AddCache<T>(this IServiceCollection services) where T : class, ICacheStrategy
        {
            services.AddSingleton<AutoCacheQueryable>();
            return services.AddSingleton<ICacheStrategy, T>();
        }

        /// <summary>
        /// 加入当前对象到缓存中  单位秒默认 7200 秒 2小时
        /// </summary>
        /// <param name="key">对象的键值</param>
        /// <param name="value">缓存的对象</param>
        public static void Add<T>(this ICacheStrategy cacheStrategy, string key, T value)
        {
            cacheStrategy.Add(key, value, 7200);
        }
        /// <summary>
        /// 获取或创建
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="cacheStrategy"></param>
        /// <param name="key"></param>
        /// <param name="createFactory"></param>
        /// <param name="seconds"></param>
        /// <returns></returns>
        public static T GetOrCreate<T>(this ICacheStrategy cacheStrategy, string key, Func<T> createFactory, int seconds)
        {
            if (TryGet<T>(cacheStrategy, key, out T result))
            {
                return result;
            }
            lock (key)
            {
                if (TryGet<T>(cacheStrategy, key, out result))
                {
                    return result;
                }
                T value = createFactory();
                if (value == null)
                {
                    return value;
                }
                cacheStrategy.Add(key, value, seconds);
                return value;
            }
        }
        private static bool TryGet<T>(ICacheStrategy cacheStrategy, string key, out T result)
        {
            result = cacheStrategy.Get<T>(key);
            if (result != null)
            {
                if (!result.Equals(default(T)))
                    return true;
                if (cacheStrategy.HasKey(key))
                    return true;
            }
            return false;
        }

        public static Task<T> GetOrCreateAsync<T>(this ICacheStrategy cacheStrategy, string key, Func<Task<T>> createFactory, int seconds)
        {
            return Task.FromResult(cacheStrategy.GetOrCreate(key, () => createFactory().GetAwaiter().GetResult(), seconds));
        }
    }
}
